package cn.itcast.fangkuai;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.*;

/***
 *
 * @author 墨染秦月
 *
 * 游戏面板类 主要功能：方块的自动下落，满行消去，计算得分，方块旋转，方块移动
 *
 */

public class GamePanel extends JPanel implements KeyListener {

	private int blockType;// 方块类型
	private int turnState;// 方块状态
	private int score = 0;// 得分
	private int nextBlockType = -1, nextTurnState = -1;// 下一个方块的类型及状态
	private int x, y;// 当前方块位置
	private Timer timer;// 定时器
	int[][] map = new int[12][21];// 游戏地图，存储方块(1~7)和围墙(-1)及空块(0)的信息
	// 方块的形状，有倒Z,Z,L,J,I,田,T七种方块
	// 存储七种形状及其旋转变形
	private final int shapes[][][] = new int[][][] {
			// 长条形I形方块
			{ { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
					{ 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 },
					{ 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
					{ 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 } },
			// 倒Z字形方块
			{ { 0, 2, 2, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
					{ 2, 0, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 },
					{ 0, 2, 2, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
					{ 2, 0, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 } },
			// Z形方块
			{ { 3, 3, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
					{ 0, 3, 0, 0, 3, 3, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0 },
					{ 3, 3, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
					{ 0, 3, 0, 0, 3, 3, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0 } },
			// J形方块
			{ { 0, 4, 0, 0, 0, 4, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0 },
					{ 4, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
					{ 4, 4, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0 },
					{ 4, 4, 4, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
			// 田字形
			{ { 5, 5, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
					{ 5, 5, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
					{ 5, 5, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
					{ 5, 5, 0, 0, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
			// L字形
			{ { 6, 0, 0, 0, 6, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0 },
					{ 6, 6, 6, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
					{ 6, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0 },
					{ 0, 0, 6, 0, 6, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
			// 倒T字形
			{ { 0, 7, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
					{ 0, 7, 0, 0, 7, 7, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0 },
					{ 7, 7, 7, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
					{ 0, 7, 0, 0, 0, 7, 7, 0, 0, 7, 0, 0, 0, 0, 0, 0 } } };

	// 生成新方块
	public void newBlock() {
		// 如果当前没有下一方块 (游戏刚开局，生成当前方块和下一方块)
		if (nextBlockType == -1 && nextTurnState == -1) {
			blockType = (int) (Math.random() * 1000) % 7;
			turnState = (int) (Math.random() * 1000) % 4;
			nextBlockType = (int) (Math.random() * 1000) % 7;
			nextTurnState = (int) (Math.random() * 1000) % 4;
		} else {// 已有下一方块
			blockType = nextBlockType;
			turnState = nextTurnState;
			nextBlockType = (int) (Math.random() * 1000) % 7;
			nextTurnState = (int) (Math.random() * 1000) % 4;
		}
		x = 4;
		y = 0;// 屏幕上方中央
		if (gameover(x, y) == 1) {// 游戏结束
			newMap();
			drawWall();
			score = 0;
			JOptionPane.showMessageDialog(null, "GAME OVER!");
		}
	}

	// 画墙方法
	public void drawWall() {
		int i, j;
		for (i = 0; i < 12; i++) {// 底部第20行画墙
			map[i][20] = -1;
		}
		for (j = 0; j < 21; j++) {// 在第0列和第11列画墙
			map[0][j] = -1;
			map[11][j] = -1;
		}
	}

	// 初始化地图
	public void newMap() {
		int i, j;
		for (i = 0; i < 12; i++) {
			for (j = 0; j < 21; j++) {
				map[i][j] = 0;
			}
		}
	}

	public GamePanel() {
		newBlock();
		newMap();
		drawWall();
		timer = new Timer(500, new TimerListener());
		timer.start();
	}

	class TimerListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent arg0) {
			if (blow(x, y + 1, blockType, turnState) == 1) {// 可以下落
				y += 1;// 当前方块下移
			} else {// 不可以下落
				add(x, y, blockType, turnState);// 固定当前方块
				delLine();// 消去满行
				newBlock();// 产生新的方块
			}
			repaint();// 屏幕重画
		}

	}

	public void turn() {
		int tempTurnState = turnState;
		turnState = (turnState + 1) % 4;
		if (blow(x, y, blockType, turnState) == 0) {// 如果不能旋转
			turnState = tempTurnState;// 恢复
		}
		repaint();
	}

	public void left() {
		if (blow(x - 1, y, blockType, turnState) == 1) {// 如果可以左移
			x -= 1;
		}
		repaint();
	}

	public void right() {
		if (blow(x + 1, y, blockType, turnState) == 1) {// 如果可以右移
			x += 1;
		}
		repaint();
	}

	public void down() {
		if (blow(x, y + 1, blockType, turnState) == 1) {// 如果可以下落
			y += 1;
		} else {
			add(x, y, blockType, turnState);
			newBlock();
			delLine();
		}
		repaint();
	}

	// 判断移动后当前方块的位置是否合法
	// 如果方块围墙或者固定的方块重叠，return 0
	public int blow(int x, int y, int blockType, int turnState) {
		for (int a = 0; a < 4; a++) {
			for (int b = 0; b < 4; b++) {
				if (((shapes[blockType][turnState][a * 4 + b] >= 1) && (map[x
						+ b + 1][y + a] >= 1))
						|| ((shapes[blockType][turnState][a * 4 + b] >= 1) && (map[x
						+ b + 1][y + a] == -1))) {
					return 0;
				}
			}
		}
		return 1;
	}

	public void delLine() {
		int c = 0;
		for (int b = 0; b < 21; b++) {
			for (int a = 0; a < 12; a++) {
				if (map[a][b] >= 1) {
					c += 1;
					if (c == 10) {// 满行消去，得10分
						score += 10;
						for (int d = b; d > 0; d--) {
							for (int e = 0; e < 12; e++) {// 方块下落
								map[e][d] = map[e][d - 1];
							}
						}
					}
				}
			}
			c = 0;
		}
	}

	public int gameover(int x, int y) {
		if (blow(x, y, blockType, turnState) == 0) {// 如果碰到围墙或固定方块，游戏结束
			return 1;
		}
		return 0;
	}

	// 将当前方块信息添加到地图数组信息中
	public void add(int x, int y, int blockType, int turnState) {
		int j = 0;
		for (int a = 0; a < 4; a++) {
			for (int b = 0; b < 4; b++) {
				if (shapes[blockType][turnState][j] >= 1) {
					map[x + b + 1][y + a] = shapes[blockType][turnState][j];
				}
				j++;
			}
		}
	}

	public void paint(Graphics g) {
		super.paint((g));// 调用父类的paint()方法，实现清屏
		int i, j;
		// 画当前方块
		for (j = 0; j < 16; j++) {
			if (shapes[blockType][turnState][j] >= 1) {

				switch (shapes[blockType][turnState][j]) {
					case 1:
						g.setColor(Color.RED);
						break;
					case 2:
						g.setColor(Color.ORANGE);
						break;
					case 3:
						g.setColor(Color.YELLOW);
						break;
					case 4:
						g.setColor(Color.GREEN);
						break;
					case 5:
						g.setColor(Color.BLUE);
						break;
					case 6:
						g.setColor(Color.PINK);
						break;
					case 7:
						g.setColor(Color.MAGENTA);
						break;
				}
				g.fillRect((j % 4 + x + 1) * 15, (j / 4 + y) * 15, 15, 15);
				g.setColor(Color.WHITE);
				g.drawRect((j % 4 + x + 1) * 15, (j / 4 + y) * 15, 15, 15);
			}
		}

		// 画已经固定的方块和围墙
		for (j = 0; j < 21; j++) {
			for (i = 0; i < 12; i++) {
				if (map[i][j] >= 1) {

					switch (map[i][j]) {
						case 1:
							g.setColor(Color.RED);
							break;
						case 2:
							g.setColor(Color.ORANGE);
							break;
						case 3:
							g.setColor(Color.YELLOW);
							break;
						case 4:
							g.setColor(Color.GREEN);
							break;
						case 5:
							g.setColor(Color.BLUE);
							break;
						case 6:
							g.setColor(Color.PINK);
							break;
						case 7:
							g.setColor(Color.MAGENTA);
							break;
					}
					g.fillRect(i * 15, j * 15, 15, 15);
					g.setColor(Color.WHITE);
					g.drawRect(i * 15, j * 15, 15, 15);
				} else if (map[i][j] == -1) {
					g.setColor(Color.gray);
					g.fillRect(i * 15, j * 15, 15, 15);
					g.setColor(Color.WHITE);
					g.drawRect(i * 15, j * 15, 15, 15);
				}
			}
		}
		g.setColor(Color.BLACK);
		g.drawString("当前分数:" + score, 225, 15);
		g.drawString("下一个方块是：", 225, 50);
		// 窗口右侧绘制下一方块
		for (j = 0; j < 16; j++) {
			if (shapes[nextBlockType][nextTurnState][j] >= 1) {
				switch (shapes[nextBlockType][nextTurnState][j]) {
					case 1:
						g.setColor(Color.RED);
						break;
					case 2:
						g.setColor(Color.ORANGE);
						break;
					case 3:
						g.setColor(Color.YELLOW);
						break;
					case 4:
						g.setColor(Color.GREEN);
						break;
					case 5:
						g.setColor(Color.BLUE);
						break;
					case 6:
						g.setColor(Color.PINK);
						break;
					case 7:
						g.setColor(Color.MAGENTA);
						break;
				}
				g.fillRect(225 + (j % 4) * 15, 100 + (j / 4) * 15, 15, 15);
				g.setColor(Color.WHITE);
				g.drawRect(225 + (j % 4) * 15, 100 + (j / 4) * 15, 15, 15);
			}
		}
	}

	// 新游戏
	public void newGame() {
		newBlock();
		newMap();
		drawWall();
	}

	// 暂停游戏
	public void pauseGame() {
		timer.stop();
	}

	// 继续游戏
	public void continueGame() {
		timer.start();
	}

	// 键盘监听
	@Override
	public void keyPressed(KeyEvent e) {
		switch (e.getKeyCode()) {
			case KeyEvent.VK_DOWN:
				down();
				break;
			case KeyEvent.VK_UP:
				turn();
				break;
			case KeyEvent.VK_RIGHT:
				right();
				break;
			case KeyEvent.VK_LEFT:
				left();
				break;
		}
	}

	@Override
	public void keyReleased(KeyEvent arg0) {

	}

	@Override
	public void keyTyped(KeyEvent arg0) {

	}

}
